'''
Created on Oct 4, 2012

@author: Himanshu
'''
import numpy as np

class oneNN():
    '''
    simple one nearest neighbor classifier. Class features are the training set and target vector.
    Training set is a list of lists and targetVector the corresponding target values.
    '''
        
    def __init__(self):
        '''
        Constructor
        '''
        self.featureSet = []
        self.targetVector = []
        
    def setTrainingSet(self,trainingSet):
        """
        Reset training set to reuse classifier
        """
        self.featureSet = trainingSet
        
    def setTargetVector(self,targetVector):
        """
        Reset target vector to reuse classifier
        """
        self.targetVector = targetVector
        
    def classify(self,query):
        """
        main classifier. Returns class of query matched against the training set. 
        """
        if (self.featureSet.__len__() == 0):
            print "Set the feature set first!"
            return
        if (self.targetVector.__len__() == 0):
            print "Set the target vector first!"
            return
        
        minNorm = float("inf")
        matchIndex = 0
        i = 0
        for instance in self.featureSet:
            if (query.__len__() < instance.__len__()):
                smallVector = query
                largeVector = instance
            else:
                smallVector = instance
                largeVector = query
            lengthDiff = largeVector.__len__() - smallVector.__len__()
            for k in range(lengthDiff):
                diff = np.subtract(smallVector, largeVector[k:(k + smallVector.__len__())])
                norm = np.linalg.norm(diff, 2)
            #norm = DTW(query, instance)
                if (norm < minNorm):
                    minNorm = norm
                    matchIndex = i
            i = i + 1
        #print minNorm
        return self.targetVector[matchIndex]
    
    def classifyW(self, query):
        if (self.featureSet.__len__() == 0):
            print "Set the feature set first!"
            return
        if (self.targetVector.__len__() == 0):
            print "Set the target vector first!"
            return
        invNorms = []
        classes = []
        i = 0
        for instance in self.featureSet:
            if (query.__len__() < instance.__len__()):
                smallVector = query
                largeVector = instance
            else:
                smallVector = instance
                largeVector = query
            lengthDiff = largeVector.__len__() - smallVector.__len__()
            minNorm = float("inf")
            for k in range(lengthDiff):
                diff = np.subtract(smallVector, largeVector[k:(k + smallVector.__len__())])
                norm = np.linalg.norm(diff, 2)
            #norm = DTW(query, instance)
                if (norm < minNorm):
                    minNorm = norm
            invNorms.append(1.0/minNorm)
            classes.append(self.targetVector[i])
            i = i + 1
        invsq = []
        for norm in invNorms:
            invsq.append(norm**2)
        #print minNorm
        return np.dot(invsq,classes)/(np.sum(invsq))
    